//
//  AirSocketServer.h
//  AirCpp
//
//  Created by Penghao on 14-1-8.
//  Copyright (c) 2014年 PengHao.

//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

#ifndef __AirCpp__AirSocketServer__
#define __AirCpp__AirSocketServer__

#include <iostream>
#include "../AirObject/AirObject.h"
#include "AirSocketConnect.h"
#include "AirBSDSocketListener.h"
#include "FreeBSD/FreeBSDSocket.h"
#include "../AirContainer/AirArray.h"
#include "../AirModle/AirSocketModel.h"
namespace AirCpp{
    
    class TestModle : AirModel {
    private:
        
    public:
        AirInt32 rssi;
        double distance;
        AirString *beacon_id;
//        AirString *data
        
        virtual AirDataStreamBuffer *stream_buffer(){
            AirDataStreamBuffer *buffer = AirDataStreamBuffer::create_instream_buffer(total_length);
            buffer->append_data(rssi);
            buffer->append_data(distance);
            
            buffer->append_data(beacon_id->length);
            buffer->append_c_data(beacon_id->c_str, beacon_id->length);
            buffer->reset_p_current();
            return buffer;
        }
        
        virtual bool prase(AirDataStreamBuffer *stream_buffer){
            stream_buffer->reset_p_current();
            stream_buffer->read_data(total_length);
            stream_buffer->read_data(rssi);
            stream_buffer->read_data(distance);
            beacon_id = new AirString();
            stream_buffer->read_data(beacon_id->length);
            beacon_id->init(beacon_id->length);
            stream_buffer->read_c_data(beacon_id->c_str, beacon_id->length);
            return true;
        }
        
        void set_rssi(AirInt32 rssi_){
            rssi = rssi_;
            total_length+= sizeof(AirInt32);
        }
        
        void set_distance(double distance_){
            distance = distance_;
            total_length += sizeof(double);
        }
        
        void set_beacon_id(AirString *beacon_id_){
            beacon_id = retain(beacon_id_);
            total_length+=sizeof(beacon_id_->length);
            total_length+=beacon_id_->length;
        }
    };
    
    
#define MAX_THREAD_NUM 4
#define MAX_OPER_PER_THREAD 100
    class AirSocketServer : public AirObject{
        typedef AirMutableArray<AirMutableArray<AirSocketConnect<AirSocketServer> >> AirConnectArrays;
        typedef AirMutableArray<AirThread<AirSocketServer>> AirThreadArray;
    protected:
        
        AirThreadArray *thread_array;
        AirConnectArrays *connect_array;
        AirFreeBSDSocketListener<AirSocketServer> *socket_listener;
        int index_thread[MAX_THREAD_NUM];
        
        virtual void *recevie_data(void *index){
            int thread_index = *(int *)index;
            if (connect_array->count()>thread_index) {
                AirMutableArray<AirSocketConnect<AirSocketServer> > *arr = (*connect_array)[thread_index];
                for (int i = 0; i < arr->count(); ++i) {
                    AirSocketConnect<AirSocketServer> *connect = (*arr)[i];
                    connect->active();
                }
            }
            return NULL;
        }
        
    public:
        AirSocketServer(){
            
        };
        
        int init(int port ,int domainType, int dataType, int protocol){
            socket_listener = new AirFreeBSDSocketListener<AirSocketServer>(this);
            if (socket_listener->init(domainType, dataType, protocol, 30) < 0) {
                delete socket_listener;
                socket_listener = NULL;
                return -1;
            }
            if (socket_listener->listen_port(port, 20) < 0) {
                delete socket_listener;
                socket_listener = NULL;
                return -1;
            }
            connect_array = new AirConnectArrays();
            socket_listener->max_connection(MAX_THREAD_NUM*MAX_OPER_PER_THREAD);
            
            thread_array = new AirThreadArray();
            for (int i = 0; i < MAX_THREAD_NUM; ++i) {
                index_thread[i] = i;
                AirThread<AirSocketServer> *reseive_thread = new AirThread<AirSocketServer>();
                reseive_thread->init();
                thread_array->add_object(reseive_thread);
                AirOperation<AirSocketServer> *operation = new AirOperation<AirSocketServer>();
                operation->init(this, &AirSocketServer::recevie_data, &index_thread[i]);
                reseive_thread->run_operation(operation);
                release(operation);
            }
            

            return 0;
        };
        
        int start(){
            if(socket_listener->start_listen(this) < 0){
                delete socket_listener;
                socket_listener = NULL;
                return -1;
            }
            return 0;
        };
        
        void stop(){
            socket_listener->stop_listen();
        }
        
        //call back
        virtual void handle_connect_request(int *socket_handle, sockaddr *client_addr){
            printf("handle_connect_request \n");
            AirSocketConnect<AirSocketServer> *conn = new AirSocketConnect<AirSocketServer>();
            if (conn->init(socket_handle, this)==0) {
                conn->active();
                unsigned long i = connect_array->count();
                AirMutableArray<AirSocketConnect<AirSocketServer>> *array = NULL;
                if (i == 0) {
                    array = new AirMutableArray<AirSocketConnect<AirSocketServer>>();
                    connect_array->add_object(array);
                }else{
                    array = (*connect_array)[i-1];
                    if (array->count()>=200) {
                        array = new AirMutableArray<AirSocketConnect<AirSocketServer>>();
                        connect_array->add_object(array);
                    }
                }
                array->add_object(conn);
                release(conn);
            }
            
        }
        virtual void received_buffer_finished(AirSocketConnect<AirSocketServer> *conn){
            
        }
        virtual void received_package(AirSocketConnect<AirSocketServer> *conn, AirDataStreamBuffer *package){
            TestModle test;
            test.prase(package);
//            AirInt32 rssi = 0;
//            double distance = 0.0;
//            AirString str;
            
//            package->read_string(&str);
//            package->read_data(&rssi);
//            package->read_data(&distance);
            printf("%s, rssi = %d, distance = %f\n", test.beacon_id->c_str, test.rssi, test.distance);
            
//            AirString re = "received_package!\n";
//            AirSocketPackageWrite w_package(200);
//            w_package.write_string(&re);
//            conn->send_package(&w_package);
        }

        virtual void connected(AirSocketConnect<AirSocketServer> *conn, bool *value){
        }
        virtual void recevie_time_out(AirSocketConnect<AirSocketServer> *conn){
            
        }
    };
    
    
}
#endif /* defined(__AirCpp__AirSocketServer__) */
